package stream;

import java8.Employee;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//StreamAPI
public class TestStreamAPI {
	//1 创建Stream
	@Test
	public void test01(){
		List<String> list=new ArrayList<>();
		//获取顺序流
		Stream<String> stream = list.stream();
		//获取并行流
		Stream<String> parallelStream = list.parallelStream();
		/**
		 * 2 获取数组流
		 */
		Function<Integer, Integer[]> fun= Integer[]::new;
		Integer[] nums = fun.apply(10);//lmabda创建数组
		//使用Arrays.stream() 获取数组stream流
		Stream<Integer> stream2 = Arrays.stream(nums);
		/**
		 * 3 通过Stream的静态方法of获取任意数据类型的流
		 */
		//参数可以是一个或多个任意类型的数据
		Stream<Integer> of = Stream.of(1,2,3,4,5);
		Stream<String> of2 = Stream.of("yaozhen");
		Stream<String> of3 = Stream.of("yozhen","何毅","崔杰");
		/**
		 * 4 创建无限流
		 */
		//参数是一个T类型,一个Function<T,T>接口的实现UnaryOperator<T,T>,即lambda,同类型参数返回同类型值
		Stream<Integer> iterate = Stream.iterate(0, (x)->x+2).limit(10); //.limit(10) 只获取前十个
		//无限流,会从0开始一直输入偶数,无限输出
		iterate.forEach(System.out::println);
		//无限生成随机数     .limit(5)取前五个
		Stream<Double> generate = Stream.generate(Math::random).limit(5).skip(2);//跳过前两个
		generate.forEach(System.out::println);
	}
	
	@Test
	public void test04(){
		//distinct:根据hascode()和equals去重,对象中需要重写方法
		emps.stream().distinct().forEach(System.out::println);
	}
	/**2 中间操作
	 * 多个中间操作可以连接起来形成一个流水线,除非流水线触发终止操作,
	 * 否则中间操作不会执行任何处理,而在终止操作时一次性全部处理,成为"惰性求值"
	 */
	@Test
	public void test02(){
		//1 筛选与切片
		Stream<Employee> stream = emps.stream().//创建流
		//filter: 接受一个断言型接口实现lambda,过滤数据,返回一个新流
		filter(e->e.getAge()<=35);
		//终止操作时 ,一次性执行中间操作
		stream.forEach(System.out::println);
	}
	@Test
	public void test03(){
		Stream<Employee> stream = emps.stream().
		filter(e->e.getSalary()>=5000)
		.skip(1)   //跳过前1个
		.limit(2);   //只取前两个,与skip合同可达到分页效果
		//终止操作时 ,一次性执行中间操作
		stream.forEach(System.out::println);
	}

	//映射
	@Test
	public void test09(){
		//map:接受一个函数,将流中每一个元素转换成其他形式,或者提取其中一部分信息,形成一个新的元素
		emps.stream().map(e->e.getName()).forEach(System.out::println);
		//将String的list转为大写输出
		List<String> list = Arrays.asList("aa","bb","cc","dd","ee","ff","gg");
		list.stream().map(String::toUpperCase).forEach(System.out::println);

		//将String转换为char输出   TestStreamAPI2::filterCharacter:返回含有char的流
		//即map返回一个流,流中的每个元素又是一个流
		Stream<Stream<Character>> map = list.stream().map(TestStreamAPI2::filterCharacter);
		//双重循环输出字符
		map.forEach((sm)->{
			//每个含有字符的流再循环
			sm.forEach(System.out::println);
		});
		//可以使用flatMap直接 完成     flatMap——接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流
		list.stream().flatMap(TestStreamAPI::filterCharacter).forEach(System.out::println);
	}

	@Test
	public void test07(){
		//进行reducing计算,工资求和1
		Optional<Double> sum = emps.stream()
				.map(Employee::getSalary)
				.collect(Collectors.reducing(Double::sum));
		System.out.println(sum.get());
		//用map-reduce计算出流中有多少个员工
		Optional<Integer> reduce = emps.stream().map((x)->1).reduce(Integer::sum);
		System.out.println(reduce.get());  //7
	}

	//将字符串转换成单个字符,返回含有字符的流
	public static Stream<Character> filterCharacter(String str){
		List<Character> list=new ArrayList<>();
		for (Character character : str.toCharArray()) {
			list.add(character);
		}
		return list.stream();
	}

	private List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "张三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
}
